Merged
Conversation
Twilio signs webhook requests using the URL without the port component, even when the publicUrl config includes a non-standard port. Add a fallback that strips the port from the verification URL when initial validation fails, matching the behavior of Twilio's official helper library. Closes openclaw#6334
…it outbound delivery flow
…y cache regression
…n basePath is set When controlUiBasePath is set, classifyControlUiRequest returned method-not-allowed (405) for all non-GET/HEAD requests under basePath, blocking plugin webhook handlers (BlueBubbles, Mattermost, etc.) from receiving POST requests. This is a 2026.3.1 regression. Return not-control-ui instead, matching the empty-basePath behavior, so requests fall through to plugin HTTP handlers. Remove the now-dead method-not-allowed type variant, handler branch, and utility function. Closes openclaw#31983 Closes openclaw#32275 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…#28204) * fix(hooks): return 200 instead of 202 for webhook responses (openclaw#22036) * docs(webhook): document 200 status for hooks agent * chore(changelog): add webhook ack note openclaw#28204 thanks @Glucksberg --------- Co-authored-by: Shakker <shakkerdroid@gmail.com>
…21208) * feat(tlon): sync with openclaw-tlon master - Add tlon CLI tool registration with binary lookup - Add approval, media, settings, foreigns, story, upload modules - Add http-api wrapper for Urbit connection patching - Update types for defaultAuthorizedShips support - Fix type compatibility with core plugin SDK - Stub uploadFile (API not yet available in @tloncorp/api-beta) - Remove incompatible test files (security, sse-client, upload) * chore(tlon): remove dead code Remove unused Urbit channel client files: - channel-client.ts - channel-ops.ts - context.ts These were not imported anywhere in the extension. * feat(tlon): add image upload support via @tloncorp/api - Import configureClient and uploadFile from @tloncorp/api - Implement uploadImageFromUrl using uploadFile - Configure API client before media uploads - Update dependency to github:tloncorp/api-beta#main * fix(tlon): restore SSRF protection with event ack tracking - Restore context.ts and channel-ops.ts for SSRF support - Restore sse-client.ts with urbitFetch for SSRF-protected requests - Add event ack tracking from openclaw-tlon (acks every 20 events) - Pass ssrfPolicy through authenticate() and UrbitSSEClient - Fixes security regression from sync with openclaw-tlon * fix(tlon): restore buildTlonAccountFields for allowPrivateNetwork The inlined payload building was missing allowPrivateNetwork field, which would prevent the setting from being persisted to config. * fix(tlon): restore SSRF protection in probeAccount - Restore channel-client.ts for UrbitChannelClient - Use UrbitChannelClient with ssrfPolicy in probeAccount - Ensures account probe respects allowPrivateNetwork setting * feat(tlon): add ownerShip to setup flow ownerShip should always be set as it controls who receives approval requests and can approve/deny actions. * chore(tlon): remove unused http-api.ts After restoring SSRF protection, probeAccount uses UrbitChannelClient instead of @urbit/http-api. The http-api.ts wrapper is no longer needed. * refactor(tlon): simplify probeAccount to direct /~/name request No channel needed - just authenticate and GET /~/name. Removes UrbitChannelClient, keeping only UrbitSSEClient for monitor. * chore(tlon): add logging for event acks * chore(tlon): lower ack threshold to 5 for testing * fix(tlon): address security review issues - Fix SSRF in upload.ts: use urbitFetch with SSRF protection - Fix SSRF in media.ts: use urbitFetch with SSRF protection - Add command whitelist to tlon tool to prevent command injection - Add getDefaultSsrFPolicy() helper for uploads/downloads * fix(tlon): restore auth retry and add reauth on SSE reconnect - Add authenticateWithRetry() helper with exponential backoff (restores lost logic from openclaw#39) - Add onReconnect callback to re-authenticate when SSE stream reconnects - Add UrbitSSEClient.updateCookie() method for proper cookie normalization on reauth * fix(tlon): add infinite reconnect with reset after max attempts Instead of giving up after maxReconnectAttempts, wait 10 seconds then reset the counter and keep trying. This ensures the monitor never permanently disconnects due to temporary network issues. * test(tlon): restore security, sse-client, and upload tests - security.test.ts: DM allowlist, group invite, bot mention detection, ship normalization - sse-client.test.ts: subscription handling, cookie updates, reconnection params - upload.test.ts: image upload with SSRF protection, error handling * fix(tlon): restore DM partner ship extraction for proper routing - Add extractDmPartnerShip() to extract partner from 'whom' field - Use partner ship for routing (more reliable than essay.author) - Explicitly ignore bot's own outbound DM events - Log mismatch between author and partner for debugging * chore(tlon): restore ack threshold to 20 * chore(tlon): sync slash commands support from upstream - Add stripBotMention for proper CommandBody parsing - Add command authorization logic for owner-only slash commands - Add CommandAuthorized and CommandSource to context payload * fix(tlon): resolve TypeScript errors in tests and monitor - Store validated account url/code before closure to fix type narrowing - Fix test type annotations for mode rules - Add proper Response type cast in sse-client mock - Use optional chaining for init properties * docs(tlon): update docs for new config options and capabilities - Document ownerShip for approval system - Document autoAcceptDmInvites and autoAcceptGroupInvites - Update status to reflect rich text and image support - Add bundled skill section - Update notes with formatting and image details - Fix pnpm-lock.yaml conflict * docs(tlon): fix dmAllowlist description and improve allowPrivateNetwork docs - Correct dmAllowlist: empty means no DMs allowed (not allow all) - Promote allowPrivateNetwork to its own section with examples - Add warning about SSRF protection implications * docs(tlon): clarify ownerShip is auto-authorized everywhere - Add ownerShip to minimal config example (recommended) - Document that owner is automatically allowed for DMs and channels - No need to add owner to dmAllowlist or defaultAuthorizedShips * docs(tlon): add capabilities table, troubleshooting, and config reference Align with Matrix docs format: - Capabilities table for quick feature reference - Troubleshooting section with common failures - Configuration reference with all options * docs(tlon): fix reactions status and expand bundled skill section - Reactions ARE supported via bundled skill (not missing) - Add link to skill GitHub repo - List skill capabilities: contacts, channels, groups, DMs, reactions, settings * fix(tlon): use crypto.randomUUID instead of Math.random for channel ID Fixes security test failure - Math.random is flagged as weak randomness. * docs: fix markdown lint - add blank line before </Step> * fix: address PR review issues for tlon plugin - upload.ts: Use fetchWithSsrFGuard directly instead of urbitFetch to preserve full URL path when fetching external images; add release() call - media.ts: Same fix - use fetchWithSsrFGuard for external media downloads; add release() call to clean up resources - channel.ts: Use urbitFetch for poke API to maintain consistent SSRF protection (DNS pinning + redirect handling) - upload.test.ts: Update mocks to use fetchWithSsrFGuard instead of urbitFetch Addresses blocking issues from jalehman's review: 1. Fixed incorrect URL being fetched (validateUrbitBaseUrl was stripping path) 2. Fixed missing release() calls that could leak resources 3. Restored guarded fetch semantics for poke operations * docs: add tlon changelog fragment * style: format tlon monitor * fix: align tlon lockfile and sse id generation * docs: fix onboarding markdown list spacing --------- Co-authored-by: Josh Lehman <josh@martian.engineering>
…bundle splitting Without this fix, the bundler can emit multiple copies of internal-hooks into separate chunks. registerInternalHook writes to one Map instance while triggerInternalHook reads from another — resulting in hooks that silently fire with zero handlers regardless of how many were registered. Reproduce: load a hook via hooks.external.entries (loader reads one chunk), then send a message:transcribed event (get-reply imports a different chunk). The handler list is empty; the hook never runs. Fix: use globalThis.__openclaw_internal_hook_handlers__ as a shared singleton. All module copies check for and reuse the same Map, ensuring registrations are always visible to triggers.
Addresses greptile review: collapses the if-guard + assignment into a single ??= expression so TypeScript can narrow the type without a non-null assertion.
…29575) * feat(feishu): add broadcast support for multi-agent group observation When multiple agents share a Feishu group chat, only the @mentioned agent receives the message. This prevents observer agents from building session memory of group activity they weren't directly addressed in. Adds broadcast support (reusing the same cfg.broadcast schema as WhatsApp) so all configured agents receive every group message in their session transcripts. Only the @mentioned agent responds on Feishu; observer agents process silently via no-op dispatchers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(feishu): guard sequential broadcast dispatch against single-agent failure Wrap each dispatchForAgent() call in the sequential loop with try/catch so one agent's dispatch failure doesn't abort delivery to remaining agents. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(feishu): avoid duplicate messages in broadcast observer mode and normalize agent IDs - Skip recordPendingHistoryEntryIfEnabled for broadcast groups when not mentioned, since the message is dispatched directly to all agents. Previously the message appeared twice in the agent prompt. - Normalize agent IDs with toLowerCase() before membership checks so config casing mismatches don't silently skip valid agents. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(feishu): set WasMentioned per-agent and normalize broadcast IDs - buildCtxPayloadForAgent now takes a wasMentioned parameter so active agents get WasMentioned=true and observers get false (P1 fix) - Normalize broadcastAgents to lowercase at resolution time and lowercase activeAgentId so all comparisons and session key generation use canonical IDs regardless of config casing (P2 fix) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(feishu): canonicalize broadcast agent IDs with normalizeAgentId * fix(feishu): match ReplyDispatcher sync return types for noop dispatcher The upstream ReplyDispatcher changed sendToolResult/sendBlockReply/ sendFinalReply to synchronous (returning boolean). Update the broadcast observer noop dispatcher to match. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(feishu): deduplicate broadcast agent IDs after normalization Config entries like "Main" and "main" collapse to the same canonical ID after normalizeAgentId but were dispatched multiple times. Use Set to deduplicate after normalization. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(feishu): honor requireMention=false when selecting broadcast responder When requireMention is false, the routed agent should be active (reply on Feishu) even without an explicit @mention. Previously activeAgentId was null whenever ctx.mentionedBot was false, so all agents got the noop dispatcher and no reply was sent — silently breaking groups that disabled mention gating. Hoist requireMention out of the if(isGroup) block so it's accessible in the dispatch code. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(feishu): cross-account broadcast dedup to prevent duplicate dispatches In multi-account Feishu setups, the same message event is delivered to every bot account in a group. Without cross-account dedup, each account independently dispatches broadcast agents, causing 2×N dispatches instead of N (where N = number of broadcast agents). Two changes: 1. requireMention=true + bot not mentioned: return early instead of falling through to broadcast. The mentioned bot's handler will dispatch for all agents. Non-mentioned handlers record to history. 2. Add cross-account broadcast dedup using a shared 'broadcast' namespace (tryRecordMessagePersistent). The first handler to reach the broadcast block claims the message; subsequent accounts skip. This handles the requireMention=false multi-account case. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(feishu): strip CommandAuthorized from broadcast observer contexts Broadcast observer agents inherited CommandAuthorized from the sender, causing slash commands (e.g. /reset) to silently execute on every observer session. Now only the active agent retains CommandAuthorized; observers have it stripped before dispatch. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(feishu): use actual mention state for broadcast WasMentioned The active broadcast agent's WasMentioned was set to true whenever requireMention=false, even when the bot was not actually @mentioned. Now uses ctx.mentionedBot && agentId === activeAgentId, consistent with the single-agent path which passes ctx.mentionedBot directly. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(feishu): skip history buffer for broadcast accounts and log parallel failures 1. In requireMention groups with broadcast, non-mentioned accounts no longer buffer pending history — the mentioned handler's broadcast dispatch already writes turns into all agent sessions. Buffering caused duplicate replay via buildPendingHistoryContextFromMap. 2. Parallel broadcast dispatch now inspects Promise.allSettled results and logs rejected entries, matching the sequential path's per-agent error logging. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Changelog: note Feishu multi-agent broadcast dispatch * Changelog: restore author credit for Feishu broadcast entry --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
…enclaw#31450) * refactor(feishu): unify Lark SDK error handling with LarkApiError - Add LarkApiError class with code, api, and context fields for better diagnostics - Add ensureLarkSuccess helper to replace 9 duplicate error check patterns - Update tool registration layer to return structured error info (code, api, context) This improves: - Observability: errors now include API name and request context for easier debugging - Maintainability: single point of change for error handling logic - Extensibility: foundation for retry strategies, error classification, etc. Affected APIs: - wiki.space.getNode - bitable.app.get - bitable.app.create - bitable.appTableField.list - bitable.appTableField.create - bitable.appTableRecord.list - bitable.appTableRecord.get - bitable.appTableRecord.create - bitable.appTableRecord.update * Changelog: note Feishu bitable error handling unification --------- Co-authored-by: echoVic <echovic@163.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
…claw#32509) * fix(feishu): correct invalid scope name in permission grant URL The Feishu API returns error code 99991672 with an authorization URL containing the non-existent scope `contact:contact.base:readonly` when the `contact.user.get` endpoint is called without the correct permission. The valid scope is `contact:user.base:readonly`. Add a scope correction map that replaces known incorrect scope names in the extracted grant URL before presenting it to the user/agent, so the authorization link actually works. Closes openclaw#31761 * chore(changelog): note feishu scope correction --------- Co-authored-by: SidQin-cyber <sidqin0410@gmail.com>
…w#31713) * feishu: pass per-group systemPrompt to inbound context The Feishu extension schema supports systemPrompt in per-group config (channels.feishu.accounts.<id>.groups.<groupId>.systemPrompt) but the value was never forwarded to the inbound context as GroupSystemPrompt. This means per-group system prompts configured for Feishu had no effect, unlike IRC, Discord, Slack, Telegram, Matrix, and other channels that already pass this field correctly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * line: pass per-group systemPrompt to inbound context Same issue as feishu: the Line config schema defines systemPrompt in per-group config but the value was never forwarded as GroupSystemPrompt in the inbound context payload. Added resolveLineGroupSystemPrompt helper that mirrors the existing resolveLineGroupConfig lookup logic (groupId > roomId > wildcard). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Changelog: note Feishu and LINE group systemPrompt propagation --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
…tent (openclaw#29616) * fix(feishu): non-blocking ws ack and preserve streaming card full content * fix(feishu): preserve fragmented streaming text without newline artifacts --------- Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
) * fix: add session-memory hook support for Feishu provider Issue openclaw#31275: Session-memory hook not triggered when using /new command in Feishu - Added command handler to Feishu provider - Integrated with OpenClaw's before_reset hook system - Ensures session memory is saved when /new or /reset commands are used * Changelog: note Feishu session-memory hook parity --------- Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
…ps (openclaw#30315) * fix(feishu): guard against false-positive @mentions in multi-app groups When multiple Feishu bot apps share a group chat, Feishu's WebSocket event delivery remaps the open_id in mentions[] per-app. This causes checkBotMentioned() to return true for ALL bots when only one was actually @mentioned, making requireMention ineffective. Add a botName guard: if the mention's open_id matches this bot but the mention's display name differs from this bot's configured botName, treat it as a false positive and skip. botName is already available via account.config.botName (set during onboarding). Closes openclaw#24249 * fix(feishu): support @ALL mention in multi-bot groups When a user sends @ALL (@_all in Feishu message content), treat it as mentioning every bot so all agents respond when requireMention is true. Feishu's @ALL does not populate the mentions[] array, so this needs explicit content-level detection. * fix(feishu): auto-fetch bot display name from API for reliable mention matching Instead of relying on the manually configured botName (which may differ from the actual Feishu bot display name), fetch the bot's display name from the Feishu API at startup via probeFeishu(). This ensures checkBotMentioned() always compares against the correct display name, even when the config botName doesn't match (e.g. config says 'Wanda' but Feishu shows '绯红女巫'). Changes: - monitor.ts: fetchBotOpenId → fetchBotInfo (returns both openId and name) - monitor.ts: store botNames map, pass botName to handleFeishuMessage - bot.ts: accept botName from params, prefer it over config fallback * Changelog: note Feishu multi-app mention false-positive guard --------- Co-authored-by: Teague Xiao <teaguexiao@TeaguedeMac-mini.local> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Automated sync from upstream stable release
v2026.3.2hit merge conflicts.sync/upstream-release-v2026.3.2Conflicted files
.gitignoredocs/providers/index.mdUpstream changes (862 commits)
Resolution
Mark this PR as Ready for review once conflicts are resolved.
This PR was created by
.github/workflows/upstream-release-sync.yml.